<?php
class Repeater extends Object
{
    public $fieldNames;
    public $template;
    public $dataSource;
    public $childKey;
    public $callback;
    public $formatted;

    public function BindRecord($row, $level = null, $index = null)
    {
        if ($this->callback)
        {
            $row = call_user_func_array($this->callback, array($row, $level, $index));
        }
        $template = $this->template;
        foreach ($this->fieldNames as $key => $field)
        {
            $value = $this->FormatValue($key, $field, $row, $level);
            $template = str_replace($key, $value, $template);
        }
        $this->formatted .= $template;
    }

    protected function FormatValue($key, $field, $row, $level)
    {
        if (!is_null($level) && $field == 'node_level') return $level;
        return Set::KeyExists($row, $field) ? Set::Get($row, $field) : $key;
    }

	public function Repeater($datasource, $template, $callback, $child_key = null)
	{
        $this->dataSource = $datasource;
        $this->template = $template;
        $this->callback = $callback;
        $this->childKey = $child_key;
		$this->fieldNames = Template::GetFieldNames($template);
	}

    public static function Render($result, $template, $callback = null)
    {
        $control = new Repeater($result, $template, $callback);
        return $control->DataBind();
    }

	public function DataBind()
	{
		foreach ($this->dataSource as $key => $row)
		{
			$this->BindRecord($row, null, $key);
		}
		return $this->formatted;
	}

    public static function RenderTree($result, $template, $childKey, $callback = array())
    {
        $control = new Repeater($result, $template, $callback, $childKey);
        return $control->TreeBind();
    }

	public function TreeBind()
	{
        TreeSet::Walk($this->dataSource, $this->childKey, array($this, 'BindRecord'));
		return $this->formatted;
	}
}
?>